/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SurfaceDrawContext_v1_DEFINED
#define SurfaceDrawContext_v1_DEFINED

#include "include/core/SkCanvas.h"
#include "include/core/SkDrawable.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurface.h"
#include "include/core/SkSurfaceProps.h"
#include "include/private/base/SkTArray.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/core/SkDevice.h"
#include "src/gpu/ganesh/GrPaint.h"
#include "src/gpu/ganesh/GrRenderTargetProxy.h"
#include "src/gpu/ganesh/GrSurfaceProxyView.h"
#include "src/gpu/ganesh/GrXferProcessor.h"
#include "src/gpu/ganesh/SurfaceFillContext.h"
#include "src/gpu/ganesh/geometry/GrQuad.h"
#include "src/gpu/ganesh/ops/OpsTask.h"

class GrBackendSemaphore;
class GrClip;
class GrColorSpaceXform;
class GrDrawOp;
class GrDstProxyView;
class GrHardClip;
class GrOp;
struct GrQuadSetEntry;
class GrRenderTarget;
class GrStyledShape;
class GrStyle;
class GrTextureProxy;
struct GrTextureSetEntry;
struct GrUserStencilSettings;
struct SkDrawShadowRec;
struct SkIPoint;
struct SkIRect;
class SkLatticeIter;
class SkMatrix;
class SkPaint;
class SkPath;
struct SkPoint;
struct SkRect;
class SkRegion;
class SkRRect;
struct SkRSXform;
class SkTextBlob;
class SkVertices;

namespace sktext {
class GlyphRunList;
}

namespace skgpu::ganesh {
/* *
 * A helper object to orchestrate commands (draws, etc...) for GrSurfaces that are GrRenderTargets.
 */
class SurfaceDrawContext final : public SurfaceFillContext {
public:
    static std::unique_ptr<SurfaceDrawContext> Make(GrRecordingContext *, GrColorType, sk_sp<GrSurfaceProxy>,
        sk_sp<SkColorSpace>, GrSurfaceOrigin, const SkSurfaceProps &);

    /* Uses the default texture format for the color type */
    static std::unique_ptr<SurfaceDrawContext> Make(GrRecordingContext *, GrColorType, sk_sp<SkColorSpace>,
        SkBackingFit, SkISize dimensions, const SkSurfaceProps &, std::string_view label, int sampleCnt = 1,
        skgpu::Mipmapped = skgpu::Mipmapped::kNo, skgpu::Protected = skgpu::Protected::kNo,
        GrSurfaceOrigin = kBottomLeft_GrSurfaceOrigin, skgpu::Budgeted = skgpu::Budgeted::kYes);

    /* *
     * Takes custom swizzles rather than determining swizzles from color type and format.
     * It will have color type kUnknown.
     */
    static std::unique_ptr<SurfaceDrawContext> Make(GrRecordingContext *, sk_sp<SkColorSpace>, SkBackingFit,
        SkISize dimensions, const GrBackendFormat &, int sampleCnt, skgpu::Mipmapped, skgpu::Protected,
        skgpu::Swizzle readSwizzle, skgpu::Swizzle writeSwizzle, GrSurfaceOrigin, skgpu::Budgeted,
        const SkSurfaceProps &, std::string_view label);

    // Same as previous factory but will try to use fallback GrColorTypes if the one passed in
    // fails. The fallback GrColorType will have at least the number of channels and precision per
    // channel as the passed in GrColorType. It may also swizzle the changes (e.g., BGRA -> RGBA).
    // SRGB-ness will be preserved.
    static std::unique_ptr<SurfaceDrawContext> MakeWithFallback(GrRecordingContext *, GrColorType, sk_sp<SkColorSpace>,
        SkBackingFit, SkISize dimensions, const SkSurfaceProps &, int sampleCnt, skgpu::Mipmapped, skgpu::Protected,
        GrSurfaceOrigin = kBottomLeft_GrSurfaceOrigin, skgpu::Budgeted = skgpu::Budgeted::kYes);

    // Creates a SurfaceDrawContext that wraps the passed in GrBackendTexture.
    static std::unique_ptr<SurfaceDrawContext> MakeFromBackendTexture(GrRecordingContext *, GrColorType,
        sk_sp<SkColorSpace>, const GrBackendTexture &, int sampleCnt, GrSurfaceOrigin, const SkSurfaceProps &,
        sk_sp<skgpu::RefCntedCallback> releaseHelper);

    SurfaceDrawContext(GrRecordingContext *, GrSurfaceProxyView readView, GrSurfaceProxyView writeView, GrColorType,
        sk_sp<SkColorSpace>, const SkSurfaceProps &);

    ~SurfaceDrawContext() override;

    /* *
     * Draw everywhere (respecting the clip) with the paint.
     */
    void drawPaint(const GrClip *, GrPaint &&, const SkMatrix &viewMatrix);

    /* *
     * Draw the rect using a paint.
     * @param paint        describes how to color pixels.
     * @param GrAA         Controls whether rect is antialiased
     * @param viewMatrix   transformation matrix
     * @param style        The style to apply. Null means fill. Currently path effects are not
     * allowed.
     * The rects coords are used to access the paint (through texture matrix)
     */
    void drawRect(const GrClip *, GrPaint &&paint, GrAA, const SkMatrix &viewMatrix, const SkRect &,
        const GrStyle *style = nullptr);

    /* *
     * Maps a rectangle of shader coordinates to a rectangle and fills that rectangle.
     *
     * @param GrPaint      describes how to color pixels.
     * @param GrAA         Controls whether rect is antialiased
     * @param SkMatrix     transformation matrix which applies to rectToDraw
     * @param rectToDraw   the rectangle to draw
     * @param localRect    the rectangle of shader coordinates applied to rectToDraw
     */
    void fillRectToRect(const GrClip *, GrPaint &&, GrAA, const SkMatrix &, const SkRect &rectToDraw,
        const SkRect &localRect);

    /* *
     * Fills a block of pixels with a paint and a localMatrix, respecting the clip.
     */
    void fillPixelsWithLocalMatrix(const GrClip *clip, GrPaint &&paint, const SkIRect &bounds,
        const SkMatrix &localMatrix)
    {
        SkRect rect = SkRect::Make(bounds);
        DrawQuad quad{ GrQuad::MakeFromRect(rect, SkMatrix::I()), GrQuad::MakeFromRect(rect, localMatrix),
            GrQuadAAFlags::kNone };
        this->drawFilledQuad(clip, std::move(paint), &quad);
    }

    /* *
     * Creates an op that draws a fill rect with per-edge control over anti-aliasing.
     *
     * This is a specialized version of fillQuadWithEdgeAA, but is kept separate since knowing
     * the geometry is a rectangle affords more optimizations.
     */
    void fillRectWithEdgeAA(const GrClip *clip, GrPaint &&paint, GrQuadAAFlags edgeAA, const SkMatrix &viewMatrix,
        const SkRect &rect, const SkRect *optionalLocalRect = nullptr)
    {
        if (edgeAA == GrQuadAAFlags::kAll) {
            this->fillRectToRect(clip, std::move(paint), GrAA::kYes, viewMatrix, rect,
                (optionalLocalRect) ? *optionalLocalRect : rect);
            return;
        }
        const SkRect &localRect = optionalLocalRect ? *optionalLocalRect : rect;
        DrawQuad quad{ GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(localRect), edgeAA };
        this->drawFilledQuad(clip, std::move(paint), &quad);
    }

    /* *
     * Similar to fillRectWithEdgeAA but draws an arbitrary 2D convex quadrilateral transformed
     * by 'viewMatrix', with per-edge control over anti-aliasing. The quad should follow the
     * ordering used by SkRect::toQuad(), which determines how the edge AA is applied:
     * - "top" = points [0] and [1]
     * - "right" = points[1] and [2]
     * - "bottom" = points[2] and [3]
     * - "left" = points[3] and [0]
     *
     * The last argument, 'optionalLocalQuad', can be null if no separate local coordinates are
     * necessary.
     */
    void fillQuadWithEdgeAA(const GrClip *clip, GrPaint &&paint, GrQuadAAFlags edgeAA, const SkMatrix &viewMatrix,
        const SkPoint points[4], const SkPoint optionalLocalPoints[4])
    {
        const SkPoint *localPoints = optionalLocalPoints ? optionalLocalPoints : points;
        DrawQuad quad{ GrQuad::MakeFromSkQuad(points, viewMatrix), GrQuad::MakeFromSkQuad(localPoints, SkMatrix::I()),
            edgeAA };
        this->drawFilledQuad(clip, std::move(paint), &quad);
    }

    // TODO(michaelludwig) - remove if the bulk API is not useful for SkiaRenderer
    void drawQuadSet(const GrClip *clip, GrPaint &&paint, const SkMatrix &viewMatrix, const GrQuadSetEntry[], int cnt);

    /* *
     * Creates an op that draws a subrectangle of a texture. The passed color is modulated by the
     * texture's color. 'srcRect' specifies the rectangle of the texture to draw. 'dstRect'
     * specifies the rectangle to draw in local coords which will be transformed by 'viewMatrix' to
     * device space.
     */
    void drawTexture(const GrClip *, GrSurfaceProxyView, SkAlphaType, GrSamplerState::Filter,
        GrSamplerState::MipmapMode, SkBlendMode, const SkPMColor4f &, const SkRect &srcRect, const SkRect &dstRect,
        GrQuadAAFlags, SkCanvas::SrcRectConstraint, const SkMatrix &, sk_sp<GrColorSpaceXform>);

    /* *
     * Variant of drawTexture that instead draws the texture applied to 'dstQuad' transformed by
     * 'viewMatrix', using the 'srcQuad' texture coordinates clamped to the optional 'subset'. If
     * 'subset' is null, it's equivalent to using the fast src rect constraint. If 'subset' is
     * provided, the strict src rect constraint is applied using 'subset'.
     */
    void drawTextureQuad(const GrClip *clip, GrSurfaceProxyView view, GrColorType srcColorType,
        SkAlphaType srcAlphaType, GrSamplerState::Filter filter, GrSamplerState::MipmapMode mm, SkBlendMode mode,
        const SkPMColor4f &color, const SkPoint srcQuad[4], const SkPoint dstQuad[4], GrQuadAAFlags edgeAA,
        const SkRect *subset, const SkMatrix &viewMatrix, sk_sp<GrColorSpaceXform> texXform)
    {
        DrawQuad quad{ GrQuad::MakeFromSkQuad(dstQuad, viewMatrix), GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()),
            edgeAA };
        this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform), filter, mm, color, mode, &quad,
            subset);
    }

    /* *
     * Draws a set of textures with a shared filter, color, view matrix, color xform, and
     * texture color xform. The textures must all have the same GrTextureType and GrConfig.
     *
     * If any entries provide a non-null fDstClip array, it will be read from immediately based on
     * fDstClipCount, so the pointer can become invalid after this returns.
     *
     * 'proxRunCnt' is the number of proxy changes encountered in the entry array. Technically this
     * can be inferred from the array within this function, but the information is already known
     * by SkGpuDevice, so no need to incur another iteration over the array.
     */
    void drawTextureSet(const GrClip *, GrTextureSetEntry[], int cnt, int proxyRunCnt, GrSamplerState::Filter,
        GrSamplerState::MipmapMode, SkBlendMode mode, SkCanvas::SrcRectConstraint, const SkMatrix &viewMatrix,
        sk_sp<GrColorSpaceXform> texXform);

    /* *
     * Draw a roundrect using a paint.
     *
     * @param paint       describes how to color pixels.
     * @param GrAA        Controls whether rrect is antialiased.
     * @param viewMatrix  transformation matrix
     * @param rrect       the roundrect to draw
     * @param style       style to apply to the rrect. Currently path effects are not allowed.
     */
    void drawRRect(const GrClip *, GrPaint &&, GrAA, const SkMatrix &viewMatrix, const SkRRect &rrect,
        const GrStyle &style);

    /* *
     * Use a fast method to render the ambient and spot shadows for a path.
     * Will return false if not possible for the given path.
     *
     * @param viewMatrix   transformation matrix
     * @param path         the path to shadow
     * @param rec          parameters for shadow rendering
     */
    bool drawFastShadow(const GrClip *, const SkMatrix &viewMatrix, const SkPath &path, const SkDrawShadowRec &rec);

    /* *
     * Draws a path.
     *
     * @param paint         describes how to color pixels.
     * @param GrAA          Controls whether the path is antialiased.
     * @param viewMatrix    transformation matrix
     * @param path          the path to draw
     * @param style         style to apply to the path.
     */
    void drawPath(const GrClip *, GrPaint &&, GrAA, const SkMatrix &viewMatrix, const SkPath &, const GrStyle &);

    /* *
     * Draws a shape.
     *
     * @param paint         describes how to color pixels.
     * @param GrAA          Controls whether the path is antialiased.
     * @param viewMatrix    transformation matrix
     * @param shape         the shape to draw
     */
    void drawShape(const GrClip *, GrPaint &&, GrAA, const SkMatrix &viewMatrix, GrStyledShape &&);

    /* *
     * Draws vertices with a paint.
     *
     * @param   paint            describes how to color pixels.
     * @param   viewMatrix       transformation matrix
     * @param   vertices         specifies the mesh to draw.
     * @param   overridePrimType primitive type to draw. If NULL, derive prim type from vertices.
     * @param   skipColorXform   if true, do not apply a color space transfer function
     */
    void drawVertices(const GrClip *, GrPaint &&paint, const SkMatrix &viewMatrix, sk_sp<SkVertices> vertices,
        GrPrimitiveType *overridePrimType = nullptr, bool skipColorXform = false);

    /* *
     * Draws a custom mesh with a paint.
     *
     * @param   paint      describes how to color pixels.
     * @param   viewMatrix transformation matrix
     * @param   mesh       the mesh to draw.
     * @param   children   child effects referenced by SkMesh shaders
     */
    void drawMesh(const GrClip *, GrPaint &&paint, const SkMatrix &viewMatrix, const SkMesh &mesh,
        skia_private::TArray<std::unique_ptr<GrFragmentProcessor>> children);

    /* *
     * Draws textured sprites from an atlas with a paint. This currently does not support AA for the
     * sprite rectangle edges.
     *
     * @param   paint           describes how to color pixels.
     * @param   viewMatrix      transformation matrix
     * @param   spriteCount     number of sprites.
     * @param   xform           array of compressed transformation data, required.
     * @param   texRect         array of texture rectangles used to access the paint.
     * @param   colors          optional array of per-sprite colors, supercedes
     * the paint's color field.
     */
    void drawAtlas(const GrClip *, GrPaint &&paint, const SkMatrix &viewMatrix, int spriteCount,
        const SkRSXform xform[], const SkRect texRect[], const SkColor colors[]);

    /* *
     * Draws a region.
     *
     * @param paint         describes how to color pixels
     * @param viewMatrix    transformation matrix
     * @param aa            should the rects of the region be antialiased.
     * @param region        the region to be drawn
     * @param style         style to apply to the region
     */
    void drawRegion(const GrClip *, GrPaint &&paint, GrAA aa, const SkMatrix &viewMatrix, const SkRegion &region,
        const GrStyle &style, const GrUserStencilSettings *ss = nullptr);

    /* *
     * Draws an oval.
     *
     * @param paint         describes how to color pixels.
     * @param GrAA          Controls whether the oval is antialiased.
     * @param viewMatrix    transformation matrix
     * @param oval          the bounding rect of the oval.
     * @param style         style to apply to the oval. Currently path effects are not allowed.
     */
    void drawOval(const GrClip *, GrPaint &&paint, GrAA, const SkMatrix &viewMatrix, const SkRect &oval,
        const GrStyle &style);

    /* *
     * Draws a partial arc of an oval.
     *
     * @param paint         describes how to color pixels.
     * @param GrGrAA        Controls whether the arc is antialiased.
     * @param viewMatrix    transformation matrix.
     * @param oval          the bounding rect of the oval.
     * @param startAngle    starting angle in degrees.
     * @param sweepAngle    angle to sweep in degrees. Must be in (-360, 360)
     * @param useCenter     true means that the implied path begins at the oval center, connects as
     * a line to the point indicated by the start contains the arc indicated by
     * the sweep angle. If false the line beginning at the center point is
     * omitted.
     * @param style         style to apply to the oval.
     */
    void drawArc(const GrClip *, GrPaint &&paint, GrAA, const SkMatrix &viewMatrix, const SkRect &oval,
        SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const GrStyle &style);

    /* *
     * Draw the image as a set of rects, specified by |iter|.
     */
    void drawImageLattice(const GrClip *, GrPaint &&, const SkMatrix &viewMatrix, GrSurfaceProxyView,
        SkAlphaType alphaType, sk_sp<GrColorSpaceXform>, GrSamplerState::Filter, std::unique_ptr<SkLatticeIter>,
        const SkRect &dst);

    /* *
     * Draw the text specified by the GlyphRunList.
     *
     * @param viewMatrix      transformation matrix
     * @param glyphRunList    text, text positions, and paint.
     */
    void drawGlyphRunList(SkCanvas *, const GrClip *, const SkMatrix &viewMatrix,
        const sktext::GlyphRunList &glyphRunList, SkStrikeDeviceInfo strikeDeviceInfo, const SkPaint &paint);

    /* *
     * Adds the necessary signal and wait semaphores and adds the passed in SkDrawable to the
     * command stream.
     */
    void drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>, const SkRect &bounds);

    // called to note the last clip drawn to the stencil buffer.
    // TODO: remove after clipping overhaul.
    void setLastClip(uint32_t clipStackGenID, const SkIRect &devClipBounds, int numClipAnalyticElements);

    // called to determine if we have to render the clip into SB.
    // TODO: remove after clipping overhaul.
    bool mustRenderClip(uint32_t clipStackGenID, const SkIRect &devClipBounds, int numClipAnalyticElements);

    void clearStencilClip(const SkIRect &scissor, bool insideStencilMask)
    {
        this->internalStencilClear(&scissor, insideStencilMask);
    }

    // While this can take a general clip, since ClipStack relies on this function, it must take
    // care to only provide hard clips or we could get stuck in a loop. The general clip is needed
    // so that path renderers can use this function.
    void stencilRect(const GrClip *clip, const GrUserStencilSettings *ss, GrPaint &&paint, GrAA doStencilMSAA,
        const SkMatrix &viewMatrix, const SkRect &rect, const SkMatrix *localMatrix = nullptr)
    {
        // Since this provides stencil settings to drawFilledQuad, it performs a different AA type
        // resolution compared to regular rect draws, which is the main reason it remains separate.
        DrawQuad quad{ GrQuad::MakeFromRect(rect, viewMatrix),
            localMatrix ? GrQuad::MakeFromRect(rect, *localMatrix) : GrQuad(rect),
            doStencilMSAA == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone };
        this->drawFilledQuad(clip, std::move(paint), &quad, ss);
    }

    // Fills the user stencil bits with a non-zero value at every sample inside the path. This will
    // likely be implemented with a Redbook algorithm, but it is not guaranteed. The samples being
    // rendered to must be zero initially.
    bool stencilPath(const GrHardClip *, GrAA doStencilMSAA, const SkMatrix &viewMatrix, const SkPath &);

    /* *
     * Draws a path, either AA or not, and touches the stencil buffer with the user stencil settings
     * for each color sample written.
     */
    bool drawAndStencilPath(const GrHardClip *, const GrUserStencilSettings *, SkRegion::Op op, bool invert,
        GrAA doStencilMSAA, const SkMatrix &viewMatrix, const SkPath &);

    skgpu::Budgeted isBudgeted() const;

    int maxWindowRectangles() const;

    /*
     * This unique ID will not change for a given SurfaceDrawContext. However, it is _NOT_
     * guaranteed to match the uniqueID of the underlying GrRenderTarget - beware!
     */
    GrSurfaceProxy::UniqueID uniqueID() const
    {
        return this->asSurfaceProxy()->uniqueID();
    }

    // Allows caller of addDrawOp to know which op list an op will be added to.
    using WillAddOpFn = void(GrOp *, uint32_t opsTaskID);
    // These perform processing specific to GrDrawOp-derived ops before recording them into an
    // op list. Before adding the op to an op list the WillAddOpFn is called. Note that it
    // will not be called in the event that the op is discarded. Moreover, the op may merge into
    // another op after the function is called (either before addDrawOp returns or some time later).
    //
    // If the clip pointer is null, no clipping will be performed.
    void addDrawOp(const GrClip *, GrOp::Owner, const std::function<WillAddOpFn> & = std::function<WillAddOpFn>());
    void addDrawOp(GrOp::Owner op)
    {
        this->addDrawOp(nullptr, std::move(op));
    }

    bool refsWrappedObjects() const
    {
        return this->asRenderTargetProxy()->refsWrappedObjects();
    }

    /* *
     * The next time this SurfaceDrawContext is flushed, the gpu will wait on the passed in
     * semaphores before executing any commands.
     */
    bool waitOnSemaphores(int numSemaphores, const GrBackendSemaphore waitSemaphores[], bool deleteSemaphoresAfterWait);

    int numSamples() const
    {
        return this->asRenderTargetProxy()->numSamples();
    }
    const SkSurfaceProps &surfaceProps() const
    {
        return fSurfaceProps;
    }
    bool canUseDynamicMSAA() const
    {
        return fCanUseDynamicMSAA;
    }
    bool wrapsVkSecondaryCB() const
    {
        return this->asRenderTargetProxy()->wrapsVkSecondaryCB();
    }

    bool alwaysAntialias() const
    {
        return fSurfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag;
    }

    GrAA chooseAA(const SkPaint &paint)
    {
        return GrAA(paint.isAntiAlias() || this->alwaysAntialias());
    }

    GrAAType chooseAAType(GrAA aa)
    {
        if (this->numSamples() > 1 || fCanUseDynamicMSAA) {
            // Always trigger DMSAA when it's available. The coverage ops that know how to handle
            // both single and multisample targets without popping will do so without calling
            // chooseAAType.
            return GrAAType::kMSAA;
        }
        return (aa == GrAA::kYes) ? GrAAType::kCoverage : GrAAType::kNone;
    }

    // This entry point should only be called if the backing GPU object is known to be
    // instantiated.
    GrRenderTarget *accessRenderTarget()
    {
        return this->asSurfaceProxy()->peekRenderTarget();
    }

#if defined(GR_TEST_UTILS)
    void testingOnly_SetPreserveOpsOnFullClear()
    {
        fPreserveOpsOnFullClear_TestingOnly = true;
    }
#endif

    void drawStrokedLine(const GrClip *, GrPaint &&, GrAA, const SkMatrix &, const SkPoint[2], const SkStrokeRec &);

private:
    enum class QuadOptimization;

    void willReplaceOpsTask(OpsTask *prevTask, OpsTask *nextTask) override;

    OpsTask::CanDiscardPreviousOps canDiscardPreviousOpsOnFullClear() const override;
    void setNeedsStencil();

    void internalStencilClear(const SkIRect *scissor, bool insideStencilMask);

    // 'stencilSettings' are provided merely for decision making purposes; When non-null,
    // optimization strategies that submit special ops are avoided.
    //
    // 'quad' should be the original draw request on input, and will be updated as
    // appropriate depending on the returned optimization level.
    //
    // If kSubmitted is returned, the provided paint was consumed. Otherwise it is left unchanged.
    QuadOptimization attemptQuadOptimization(const GrClip *clip, const GrUserStencilSettings *stencilSettings,
        DrawQuad *quad, GrPaint *paint);

    // The overall AA policy is determined by the quad's edge flags: kNone is no AA, and anything
    // else uses some form of anti-aliasing. If 'ss' is non-null, that will be MSAA; otherwise it's
    // MSAA or analytic coverage per chooseAAType(). This will always attempt to apply
    // quad optimizations, so all quad/rect public APIs should rely on this function for consistent
    // clipping behavior. 'quad' will be modified in place to reflect final rendered geometry.
    void drawFilledQuad(const GrClip *clip, GrPaint &&paint, DrawQuad *quad, const GrUserStencilSettings *ss = nullptr);

    // Like drawFilledQuad but does not require using a GrPaint or FP for texturing.
    // 'quad' may be modified in place to reflect final geometry.
    void drawTexturedQuad(const GrClip *clip, GrSurfaceProxyView proxyView, SkAlphaType alphaType,
        sk_sp<GrColorSpaceXform> textureXform, GrSamplerState::Filter filter, GrSamplerState::MipmapMode,
        const SkPMColor4f &color, SkBlendMode blendMode, DrawQuad *quad, const SkRect *subset = nullptr);

    // Tries to detect if the given shape is a simple, and draws it without path rendering if
    // we know how.
    bool drawSimpleShape(const GrClip *, GrPaint *, GrAA, const SkMatrix &, const GrStyledShape &);

    // If 'attemptDrawSimple' is true, of if the original shape is marked as having been simplfied,
    // this will attempt to re-route through drawSimpleShape() to see if we can avoid path rendering
    // one more time.
    void drawShapeUsingPathRenderer(const GrClip *, GrPaint &&, GrAA, const SkMatrix &, GrStyledShape &&,
        bool attemptDrawSimple = false);

    // Makes a copy of the proxy if it is necessary for the draw and places the texture that should
    // be used by GrXferProcessor to access the destination color in 'result'. If the return
    // value is false then a texture copy could not be made.
    //
    // The op should have already had setClippedBounds called on it.
    [[nodiscard]] bool setupDstProxyView(const SkRect &opBounds, bool opRequiresMSAA, GrDstProxyView *result);

    OpsTask *replaceOpsTaskIfModifiesColor();

    const SkSurfaceProps fSurfaceProps;
    const bool fCanUseDynamicMSAA;

    bool fNeedsStencil = false;

#if defined(GR_TEST_UTILS)
    bool fPreserveOpsOnFullClear_TestingOnly = false;
#endif
};
} // namespace skgpu::ganesh

#endif // SurfaceDrawContext_v1_DEFINED
